const { workerData, parentPort } = require('worker_threads')
const fs = require('fs')
const readline = require('readline')

/**
 * isPm2Hosting 是否为PM2托管
 * logFilePath 日志文件路径
 * start web worker切割日志文件开始位置
 * end web worker切割日志文件结束位置
 * timeRange 需要匹配的时间范围
 */
const { isPm2Hosting, logFilePath, start, end, timeRange } = workerData

// 用于存储包下载总量的对象
const downloadStats = {}

// 统计不同时间段的包下载量
const periodStats = {
  dayStats: {}, // 最近一天
  lastWeek: {}, // 最近一周
  thisWeek: {}, // 本周
  lastMonth: {}, // 最近一月
  thisMonth: {} // 本月
}

// 正则表达式匹配日志行(兼容verdaccio和PM2,同时匹配不含时间戳原日志,兼容含有ANSI码颜色日志)
const pattern1 =
  /http\s+<--\s+(?:\x1b\[[0-9;]*m)?(200|304)(?:\x1b\[[0-9;]*m)?,\s+user:\s+(?:\x1b\[[0-9;]*m)?(\w+)(?:\x1b\[[0-9;]*m)?\(([\d.]+)\),\s+req:\s+'GET\s+\/([^']+)',\s+bytes:\s+(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?\/(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?/ // verdaccio
const pattern2 =
  /http\s+---\s+(?:\x1b\[[0-9;]*m)?(200|304)(?:\x1b\[[0-9;]*m)?,\s+user:\s+(?:\x1b\[[0-9;]*m)?(\w+)(?:\x1b\[[0-9;]*m)?\(([\d.]+)\),\s+req:\s+'GET\s+\/([^']+)',\s+bytes:\s+(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?\/(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?/ // PM2
const pattern3 =
  /\[(.*?)\] http\s+<--\s+(?:\x1b\[[0-9;]*m)?(200|304)(?:\x1b\[[0-9;]*m)?,\s+user:\s+(?:\x1b\[[0-9;]*m)?(\w+)(?:\x1b\[[0-9;]*m)?\(([\d.]+)\),\s+req:\s+'GET\s+\/([^']+)',\s+bytes:\s+(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?\/(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?/ // verdaccio
const pattern4 =
  /\[(.*?)\]http\s+---\s+(?:\x1b\[[0-9;]*m)?(200|304)(?:\x1b\[[0-9;]*m)?,\s+user:\s+(?:\x1b\[[0-9;]*m)?(\w+)(?:\x1b\[[0-9;]*m)?\(([\d.]+)\),\s+req:\s+'GET\s+\/([^']+)',\s+bytes:\s+(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?\/(?:\x1b\[[0-9;]*m)?(\d+)(?:\x1b\[[0-9;]*m)?/ // PM2

const log_Pattern = isPm2Hosting ? pattern2 : pattern1
const log_TimePattern = isPm2Hosting ? pattern4 : pattern3

// 创建逐行读取日志的流
const fileStream = fs.createReadStream(logFilePath, { start, end })
const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity })

// 逐行读取日志
rl.on('line', (line) => {
  // 过滤状态码为200/304的下载日志,兼容含有ANSI码颜色日志
  if (line.includes('200') || line.includes('304') || line.includes('ESC[33m200ESC[39m') || line.includes('ESC[33m304ESC[39m')) {
    // 正则匹配下载总量
    const match = line.match(log_Pattern)
    if (match) {
      /**
       *l 匹配到的行
       *_ 匹配到的行号
       *user 匹配到的用户名
       *ip 匹配到的IP地址
       *path 匹配到的路径
       *bytesSent 匹配到的发送字节数
       *bytesReceived 匹配到的接收字节数
       */
      const [l, _, user, ip, packageName, bytesSent, bytesReceived] = match

      // 统计总数
      downloadStats[packageName] = (downloadStats[packageName] || 0) + 1
    }

    const matchTime = line.match(log_TimePattern)
    if (matchTime) {
      // t 匹配到的时间
      const [l, t, _, user, ip, packageName, bytesSent, bytesReceived] = matchTime
      const logTimeStr = t

      // 解析日志时间
      const logTime = new Date(logTimeStr).getTime()

      updatePeriodStats('lastWeek', logTime, packageName, timeRange.agoTime[0])
      updatePeriodStats('lastMonth', logTime, packageName, timeRange.agoTime[1])
      updatePeriodStats('dayStats', logTime, packageName, timeRange.dayTime[0], timeRange.dayTime[1])
      updatePeriodStats('thisWeek', logTime, packageName, timeRange.weekTime[0], timeRange.weekTime[1])
      updatePeriodStats('thisMonth', logTime, packageName, timeRange.monthTime[0], timeRange.monthTime[1])
    }
  }
})

function updatePeriodStats(period, logTime, packageName, startTime, endTime) {
  if (logTime >= startTime && (endTime === undefined || logTime <= endTime)) {
    periodStats[period][packageName] = (periodStats[period][packageName] || 0) + 1
  }
}

// 读取完成后返回结果
rl.on('close', () => {
  parentPort.postMessage({
    downloadStats,
    ...periodStats
  })
})

// 捕获错误并返回空结果
rl.on('error', (error) => {
  parentPort.postMessage(null)
})
